import {
  CRC16,
  stringToAsciiBytes,
  bytesToInt,
  hexStr2Bytes,
  MsgType,
  DeviceMessageSend,
  DeviceMessageReceive,
  CommonConfirmReplyMsgBody,
  RecipeSendMsgBody,
  RecipeStepInfo,
  RecipeStartCookingMsgBody,
  ElectronicScaleFoodPreparationMsgBody,
  FoodWeightInfo,
  RangeHoodFanControlMsgBody,
  SettingSeasoningRatioCalibrationMsgBody,
  SeasoningRatioCalibrationInfo,
  ManualAddSeasoningMsgBody,
  SeasoningAddInfo,
  SettingSeasoningBaseUnitMsgBody
} from '@/utils/deviceProtocolUtil.js'

import {
  DeviceModel,
  DeviceStatus,
  DevicePeripheralType
} from '@/interface/device.js'

import { deviceProtocolListenerService } from './deviceProtocolListenerService'
import { DeviceProtocolBase } from './DeviceProtocolBase'
import { CookItemStatus } from '../interface/cooking'

/**
 * 设备菜谱协议服务
 */
class DeviceProtocolRecipeService extends DeviceProtocolBase {
  constructor() {
    super()
  }

  /**
   * 发送菜谱
   * @param {deviceInfo} device 设备信息
   * @param {downloadRecipeInfo} recipe 菜谱数据信息
   */
  sendRecipe(device, recipe) {
    if (device == null || recipe == null) {
      return new Promise((resolve, reject) => {
        reject('设备或者菜谱数据为空')
      })
    }

    const { getAnGoalByDeviceAndIngredient } = useCookingStore()

    let deviceSn = device.sn
    g_utils.writeLog('准备封装【发送菜谱】命令')
    g_utils.writeLog('设备信息：', device)
    g_utils.writeLog('菜谱信息：', recipe)
    // 这里需要转换，根据菜谱信息封装成对应的设备菜谱报文
    let stepList = []
    for (let index = 0; index < recipe.stepList.length; index++) {
      let step = recipe.stepList[index]
      let targetPeripheralItem = device.peripheralList.find(
        ele => ele.ingredientCode == step.targetId
      )
      if (!targetPeripheralItem) {
        return new Promise((resolve, reject) => {
          reject(`设备配置无法满足菜谱步骤${index + 1}的要求：${step.name}"`)
        })
      }
      let targetId = bytesToInt(hexStr2Bytes(targetPeripheralItem.driverId))
      let goal = 0
      if (targetPeripheralItem.type == DevicePeripheralType.FoodBox) {
        goal = step.turnCount
      } else if ([2,3,4,5].includes(targetPeripheralItem.type)) {
        goal = getAnGoalByDeviceAndIngredient(targetPeripheralItem.ingredientCode, device, step.goal)
      } else {
        goal = step.goal
      }
      stepList.push(
        new RecipeStepInfo(
          /*步骤时长（秒）*/ step.timeOffset,
          /*设备地址*/ targetId,
          /*执行目标*/ goal
        )
      )
    }

    g_utils.writeLog('准备发送【发送菜谱】命令给设备：', deviceSn)
    let recipeSendMsgBody = new RecipeSendMsgBody(recipe.id, stepList)
    console.log('准备发送【发送菜谱】recipeSendMsgBody：', recipeSendMsgBody)
    // 封装成发送消息
    let deviceMessageSendEntity = new DeviceMessageSend(
      deviceSn,
      MsgType.RecipeSend,
      recipeSendMsgBody
    )
    let deviceReplyMsgPredicate = msg => {
      // msg 是一个 DeviceMessageReceive 数据类型
      g_utils.writeLog('【发送菜谱】命令断言函数参数：', msg)
      let b = msg.msgBody.result > 0
      let status = msg.msgBody.status // 正确返回菜谱总步骤数
      if (b) {
        g_utils.writeLog('发送【发送菜谱】命令成功')
      } else {
        g_utils.writeLog('发送【发送菜谱】命令失败')
      }
      return b
    }
    return this.deviceProtocolStore.sendMessageWithReplyPredicate(
      deviceMessageSendEntity,
      deviceReplyMsgPredicate
    )
  }

  /**
   * 开始炒菜
   * @param {String} deviceSn 设备SN号
   * @param {String} recipeId 菜谱ID
   */
  startCooking(deviceSn, recipeId) {
    g_utils.writeLog('准备发送【开始炒菜】命令给设备：', deviceSn)
    let msgBody = new RecipeStartCookingMsgBody(recipeId)

    // 封装成发送消息
    let deviceMessageSendEntity = new DeviceMessageSend(
      deviceSn,
      MsgType.RecipeStartCooking,
      msgBody
    )
    let deviceReplyMsgPredicate = msg => {
      // msg 是一个 DeviceMessageReceive 数据类型
      g_utils.writeLog('【开始炒菜】命令断言函数参数：', msg)
      // 设备接收后，正确则回复当前工作状态为炒菜状态值，错误则回复0x0
      let b = msg.msgBody.result > 0
      // 正确时返回工作状态 1：自动烹饪 8：手动烹饪
      let status = msg.msgBody.status
      if (b) {
        g_utils.writeLog('发送【开始炒菜】命令成功')
      } else {
        g_utils.writeLog('发送【开始炒菜】命令失败')
      }
      return b
    }
    return this.deviceProtocolStore.sendMessageWithReplyPredicate(
      deviceMessageSendEntity,
      deviceReplyMsgPredicate
    )
  }

  /**
   * 暂停炒菜
   * @param {String} deviceSn 设备SN号
   */
  pauseCooking(deviceSn) {
    g_utils.writeLog('准备发送【暂停炒菜】命令给设备：', deviceSn)

    // 封装成发送消息
    let deviceMessageSendEntity = new DeviceMessageSend(
      deviceSn,
      MsgType.RecipePauseCooking,
      null
    )
    let deviceReplyMsgPredicate = msg => {
      // msg 是一个 DeviceMessageReceive 数据类型
      g_utils.writeLog('【暂停炒菜】命令断言函数参数：', msg)
      // 设备接收后，回复设备当前工作状态信息 CommonConfirmReplyMsgBody
      let b = msg.msgBody.result > 0
      let status = msg.msgBody.status // 正确则回复 暂停时的步骤序号
      if (b) {
        g_utils.writeLog('发送【暂停炒菜】命令成功')
        // 记录烹饪步骤暂停的时间
        let cookingStore = useCookingStore()
        let targetCookItem = cookingStore.getLatestCookInfoForDevice(deviceSn)
        if (targetCookItem && targetCookItem.cookStartTime > 0) {
          targetCookItem.stepPauseStartTime = Date.now()
          if (!targetCookItem.stepPauseDuration) {
              targetCookItem.stepPauseDuration = 0
          }
          targetCookItem.status = CookItemStatus.Pause
        }
      } else {
        g_utils.writeLog('发送【暂停炒菜】命令失败')
      }

      // TODO: 记录最后设备烹饪的状态信息
      g_utils.writeLog('准备更新设备状态信息：', msg.msgBody)
      return b
    }
    return this.deviceProtocolStore.sendMessageWithReplyPredicate(
      deviceMessageSendEntity,
      deviceReplyMsgPredicate
    )
  }

  /**
   * 继续炒菜
   * @param {String} deviceSn 设备SN号
   */
  resumeCooking(deviceSn) {
    g_utils.writeLog('准备发送【继续炒菜】命令给设备：', deviceSn)

    // 封装成发送消息
    let deviceMessageSendEntity = new DeviceMessageSend(
      deviceSn,
      MsgType.RecipeResumeCooking,
      null
    )
    let deviceReplyMsgPredicate = msg => {
      // msg 是一个 DeviceMessageReceive 数据类型
      g_utils.writeLog('【继续炒菜】命令断言函数参数：', msg)
      // 设备接收后，回复结果 CommonConfirmReplyMsgBody
      let b = msg.msgBody.result > 0
      let status = msg.msgBody.status // 正确则回复当前状态为“自动烹饪状态”
      if (b) {
        g_utils.writeLog('发送【继续炒菜】命令成功')
        // 记录烹饪步骤暂停的时间
        let cookingStore = useCookingStore()
        let targetCookItem = cookingStore.getLatestCookInfoForDevice(deviceSn)
        if (targetCookItem && targetCookItem.cookStartTime > 0) {
          let pauseTime = Date.now() - targetCookItem.stepPauseStartTime
          targetCookItem.stepPauseDuration += pauseTime
          targetCookItem.status = CookItemStatus.Cooking
        }
      } else {
        g_utils.writeLog('发送【继续炒菜】命令失败')
      }

      // TODO: 记录设备烹饪的状态信息
      g_utils.writeLog('准备更新设备状态信息：', msg.msgBody)
      return b
    }
    return this.deviceProtocolStore.sendMessageWithReplyPredicate(
      deviceMessageSendEntity,
      deviceReplyMsgPredicate
    )
  }
  /**
   * 终止炒菜
   * @param {String} deviceSn 设备SN号
   */
  stopCooking(deviceSn) {
    g_utils.writeLog('准备发送【终止炒菜】命令给设备：', deviceSn)

    // 封装成发送消息
    let deviceMessageSendEntity = new DeviceMessageSend(
      deviceSn,
      MsgType.RecipeStopCooking,
      null
    )
    let deviceReplyMsgPredicate = msg => {
      // msg 是一个 DeviceMessageReceive 数据类型
      g_utils.writeLog('【终止炒菜】命令断言函数参数：', msg)
      // 设备接收后，回复结果 CommonConfirmReplyMsgBody
      let b = msg.msgBody.result > 0
      let status = msg.msgBody.status // 正确则回复 烹饪完成状态3
      if (b) {
        g_utils.writeLog('发送【终止炒菜】命令成功')
      } else {
        g_utils.writeLog('发送【终止炒菜】命令失败')
      }

      // TODO: 记录设备烹饪的状态信息
      g_utils.writeLog('准备更新设备状态信息：', msg.msgBody)
      return b
    }
    return this.deviceProtocolStore.sendMessageWithReplyPredicate(
      deviceMessageSendEntity,
      deviceReplyMsgPredicate
    )
  }

  /**
   * 开始出菜
   * @param {String} deviceSn 设备SN号
   */
  startPlating(deviceSn) {
    g_utils.writeLog('准备发送【开始出菜】命令给设备：', deviceSn)

    // 封装成发送消息
    let deviceMessageSendEntity = new DeviceMessageSend(
      deviceSn,
      MsgType.RecipeStartPlating,
      null
    )
    let deviceReplyMsgPredicate = msg => {
      // msg 是一个 DeviceMessageReceive 数据类型
      g_utils.writeLog('【开始出菜】命令断言函数参数：', msg)
      // 设备接收后，回复结果 CommonConfirmReplyMsgBody
      let b = msg.msgBody.result > 0
      let status = msg.msgBody.status // 正确则回复收到的信息：正在出菜
      if (b) {
        g_utils.writeLog('发送【开始出菜】命令成功')
      } else {
        g_utils.writeLog('发送【开始出菜】命令失败')
      }

      // TODO: 记录设备烹饪的状态信息
      g_utils.writeLog('准备更新设备状态信息：', msg.msgBody)
      return b
    }
    return this.deviceProtocolStore.sendMessageWithReplyPredicate(
      deviceMessageSendEntity,
      deviceReplyMsgPredicate
    )
  }
  /**
   * 完成出菜
   * @param {String} deviceSn 设备SN号
   */
  finishPlating(deviceSn) {
    g_utils.writeLog('准备发送【完成出菜】命令给设备：', deviceSn)

    // 封装成发送消息
    let deviceMessageSendEntity = new DeviceMessageSend(
      deviceSn,
      MsgType.RecipeFinishPlating,
      null
    )
    let deviceReplyMsgPredicate = msg => {
      // msg 是一个 DeviceMessageReceive 数据类型
      g_utils.writeLog('【完成出菜】命令断言函数参数：', msg)
      // 设备接收后，回复结果 CommonConfirmReplyMsgBody
      let b = msg.msgBody.result > 0
      let status = msg.msgBody.status // 正确则回复：正在复位
      if (b) {
        g_utils.writeLog('发送【完成出菜】命令成功')
      } else {
        g_utils.writeLog('发送【完成出菜】命令失败')
      }

      // TODO: 记录设备烹饪的状态信息
      g_utils.writeLog('准备更新设备状态信息：', msg.msgBody)
      return b
    }
    return this.deviceProtocolStore.sendMessageWithReplyPredicateAndTimeout(
      deviceMessageSendEntity,
      deviceReplyMsgPredicate,
      20
    )
  }
  /**
   * 开始自动洗锅
   * @param {String} deviceSn 设备SN号
   */
  startAutoWashPot(deviceSn) {
    g_utils.writeLog('准备发送【开始自动洗锅】命令给设备：', deviceSn)

    // 封装成发送消息
    let deviceMessageSendEntity = new DeviceMessageSend(
      deviceSn,
      MsgType.RecipeStartAutoWashPot,
      null
    )
    let deviceReplyMsgPredicate = msg => {
      // msg 是一个 DeviceMessageReceive 数据类型
      g_utils.writeLog('【开始自动洗锅】命令断言函数参数：', msg)
      // 设备接收后，回复结果 CommonConfirmReplyMsgBody
      let b = msg.msgBody.result > 0
      let status = msg.msgBody.status // 正确则回复 自动洗锅的状态
      if (b) {
        g_utils.writeLog('发送【开始自动洗锅】命令成功')
      } else {
        g_utils.writeLog('发送【开始自动洗锅】命令失败')
      }

      // TODO: 记录设备烹饪的状态信息
      g_utils.writeLog('准备更新设备状态信息：', msg.msgBody)
      return b
    }
    return this.deviceProtocolStore.sendMessageWithReplyPredicate(
      deviceMessageSendEntity,
      deviceReplyMsgPredicate
    )
  }
}

export const deviceProtocolRecipeService = new DeviceProtocolRecipeService()
